#include "TcpConnection.h"
#include "log.h"
#include "Socket.h"
#include "Channel.h"
#include "EventLoop.h"
#include <functional>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <netinet/tcp.h>
#include <string>
// #include"EventLoop.h"
static EventLoop *CheckLoopNotNull(EventLoop *loop)
{
    if (loop == nullptr)
    {
        LOG_FATAL("%s:%s:%d TcpConnectionLoop is null\n", __FILE__, __FUNCTION__, __LINE__);
    }
    return loop;
}
// TcpConnection::TcpConnection(EventLoop *loop,
//                              const std::string &name,
//                              int socket,
//                              const InetAddress &localAddr,
//                              const InetAddress &peerAddr):loop_(CheckLoopNotNull(loop)), name_(name), state_(kConnecting), reading_(true){}

TcpConnection::TcpConnection(EventLoop *loop,
                             const std::string &name,
                             int socket,
                             const InetAddress &localAddr,
                             const InetAddress &peerAddr) : loop_(CheckLoopNotNull(loop)),
                                                      name_(name),
                                                      state_(kConnecting),
                                                      reading_(true),
                                                      socket_(new Socket(socket)),
                                                      channel_(new Channel(loop, socket)),
                                                      localAddr_(localAddr),
                                                      peerAddr_(peerAddr),
                                                      highWaterMark_(64 * 1024 * 1024)
{
    // 给channel设置相应的回调函数,当poller通知给channel感兴趣的事情发生了,channel会回应相应的操作函数
    channel_->ReadCallBack(std::bind(&TcpConnection::handleRead, this, std::placeholders::_1));
    channel_->writeCallBack(std::bind(&TcpConnection::handleWrite, this));
    channel_->closeCallBack(std::bind(&TcpConnection::handleClose, this));
    channel_->errorCallBack(std::bind(&TcpConnection::handleError, this));
    LOG_INFO("TcpConnection::ctor[%s] at fd=%d\n", name_.c_str(), socket);
    socket_->setKeepAlive(true);
}

TcpConnection::~TcpConnection()
{
    LOG_INFO("TcpConnection::ctor[%s] at fd=%d state=%d\n", name_.c_str(), channel_->fd(), (int)state_);
}

void TcpConnection::connectionEstablished()
{
    setstate(kConnected);
    channel_->tie(shared_from_this());
    channel_->enableReading(); // 向poller注册channel的读事件
    // 新连接建立,执行回调

    connectionCallback_(shared_from_this());
}

void TcpConnection::shutdown()
{
    if (state_ == kConnected)
    {
        setstate(kDisconnecting);
        loop_->runInLoop(std::bind(&TcpConnection::shutdownInLoop, this));
    }
}
void TcpConnection::shutdownInLoop()
{
    if (!channel_->isWriting())
    { // 说明outputBuffer中的数据已经发送完成
        socket_->shutdownWrite();
    }
}
void TcpConnection::connectionDestoryed()
{
    if (state_ == kConnected)
    {
        setstate(kDisconnected);
        channel_->disableAll(); // 将所有channel感兴趣的事件从poller中取消掉
        connectionCallback_(shared_from_this());
    }
    channel_->remove(); // 把channel从poller中删除
}
void TcpConnection::handleRead(TimeStamp receiveTime)
{
    int saveErrno = 0;
    ssize_t n = inputBuffer_.readFd(channel_->fd(), &saveErrno);
    if (n > 0)
    {
        // 表示已建立链接的用户已经有可读的事情发生了,调用用户传入的回调操作Onmassage
        messageCallback_(shared_from_this(), &inputBuffer_, receiveTime);
    }
    else if (n == 0)
    {
        handleClose();
    }
    else
    {
        errno = saveErrno;
        LOG_ERROR("TcpConnection::handleRead");
        handleError();
    }
}
void TcpConnection::handleWrite()
{
    if (channel_->isWriting())
    {
        int saveErrno = 0;
        ssize_t n = outputBuffer_.writefd(channel_->fd(), &saveErrno);
        if (n > 0)
        {
            outputBuffer_.retrieve(n);
            if (outputBuffer_.readableBytes() == 0)
            {
                channel_->disableReading();
                if (writeCompleteCallback_)
                {
                    // 唤醒loop所在的线程执行回调
                    loop_->queueInLoop(
                        std::bind(writeCompleteCallback_, shared_from_this()));
                }
                if (state_ == kDisconnecting)
                {
                    shutdownInLoop();
                }
            }
        }
        else
        {
            LOG_ERROR("TcpCOnnection::hanldeWrite)");
        }
    }
    else
    {
        LOG_ERROR("TcpConnection fd=%d is down,no more writing \n", channel_->fd());
    }
}
// poller=>channel::closeCallback=>TcpConnection::handleClose()
void TcpConnection::handleClose()
{
    LOG_INFO("fd=%d state=%d \n", channel_->fd(), (int)state_);
    setstate(kDisconnected);
    channel_->disableAll();
    TcpConnectionPtr connPtr(shared_from_this());
    connectionCallback_(connPtr); // 执行链接关闭的回调
    closeCallback_(connPtr);
}
void TcpConnection::handleError()
{
    int optval;
    socklen_t optlen = sizeof optval;
    int err = 0;
    if (::getsockopt(channel_->fd(), SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0)
    {
        err = errno;
    }
    else
    {
        err = optval;
    }
    LOG_ERROR("TcpConnection::handlerError name :%s -SO_ERROR:%d \n", name_.c_str(), err);
}
void TcpConnection::send(const std::string &buf)
{
    if (state_ == kConnected)
    {
        if (loop_->isInLoopThread())
        {
            sendInLoop(buf.c_str(), buf.size());
        }
        else
        {
            loop_->runInLoop(std::bind(&TcpConnection::sendInLoop, this, buf.c_str(), buf.size()));
        }
    }
}
/**
 * //发送数据,因为应用写的快,而内核发送数据较慢,因此需要把待发送数据写入缓冲区,而且设置了水位回调函数,
 */

void TcpConnection::sendInLoop(const void *message, size_t len)
{
    ssize_t nwrote = 0;
    size_t remaining = len;
    bool faultError = false;
    if (state_ == kDisconnected)
    { // 连接断开,不能发送数据
        LOG_ERROR("disconnected,giveupwriting");
        return;
    } // 表示当前没有数据要发送,并且outputBuffer_为空
    if (!channel_->isWriting() && outputBuffer_.readableBytes() == 0)
    {
        nwrote = ::write(channel_->fd(), message, len);
        if (nwrote >= 0)
        {
            remaining = len - nwrote;
            if (remaining == 0 && writeCompleteCallback_)
            {
                // 既然在这里一次性数据全部发送完成,就不用再给channel设置epollout事件了
                loop_->queueInLoop(std::bind(writeCompleteCallback_, shared_from_this()));
            }
        }
        else
        {
            nwrote = 0;
            if (errno != EWOULDBLOCK)
            {
                LOG_ERROR("TcpConnection::sendInLoop");
                if (errno == EPIPE || errno == ECONNRESET)
                {
                    faultError = true;
                }
            }
        }
    }
    // 说明这一次的发送没有把数据全部发送完毕,剩余的数据需要保存到缓冲区中当中,并且channel需要设置可写事件
    // 注册epollout事件，当内核发送缓冲区可写时，会通知相应的socket描述符，此时会调用channel的handlerEvent
    // 也就是调用TcpConnection::handleWrite方法,把发送缓冲区中的数据发送给对端

    if (!faultError && remaining > 0)
    {
        // 目前发送缓冲区剩余的带发送数据的长度
        size_t oldlen = outputBuffer_.readableBytes();
        if (oldlen + remaining >= highWaterMark_ && oldlen < highWaterMark_ && highWaterMarkCallback_)
        {
            loop_->queueInLoop(std::bind(highWaterMarkCallback_, shared_from_this(), oldlen + remaining));
        }
        outputBuffer_.append((char *)message + nwrote, remaining);
        if (!channel_->isWriting())
        {
            channel_->enableWriting(); // 注册写事件,否则不会channel不会给epoll注册写事件
        }
    }
}
